// Copyright (c) 1996-2002 John Lyon-Smith. All rights reserved.

#pragma once

#include <wxtl\Base.h>

namespace wxtl
{
	// Interlocked increment/decrement and exchange
	template<class T> T _stdcall Increment(T* x) 
	{ 
		return (T)InterlockedIncrement((LONG*)x); 
	}
	
	template<class T> T _stdcall Decrement(T* x) 
	{ 
		return (T)InterlockedDecrement((LONG*)x); 
	}
	
	template<class T> T _stdcall Exchange(T* x, T y) 
	{ 
		return (T)InterlockedExchange((LONG*)x, (LONG)y); 
	}

	// ATL does this too (just try it without)
	#ifdef _M_IX86
	#undef InterlockedExchangePointer
	inline void* _stdcall InterlockedExchangePointer(void** pp, void* pNew) throw()
	{
		return (reinterpret_cast<void*>(static_cast<LONG_PTR>(
			::InterlockedExchange(
				reinterpret_cast<LONG*>(pp), static_cast<LONG>(reinterpret_cast<LONG_PTR>(pNew))))) );
	}
	#endif

	template<class T> T _stdcall ExchangePtr(T* x, T y) 
		{ return (T)InterlockedExchangePointer((PVOID*)x, (PVOID)y); }

	struct SpinLock
	{
		SpinLock()
			:m_spin(0)
			,m_lockSpinCount(0)
		{

		}
		~SpinLock()
		{
			 Unlock();
		}
		void Lock()
		{
			 while( ::InterlockedExchange( &m_spin, 1 ) == 1 )m_lockSpinCount++;
			 if(m_lockSpinCount)
			 {
				printf("Spinlock took %i cycles\n", m_lockSpinCount);
			 }
			 //m_lockSpinCount = 0;
		}

		void Unlock()
		{
			::InterlockedExchange( &m_spin, 0 );
		}
		volatile LONG m_spin;
		int m_lockSpinCount;
	};

	class SpinLockScope
	{
	public:
		SpinLockScope(SpinLock* lock)
			:m_lock(lock)
		{
			m_lock->Lock();
		}
		~SpinLockScope()
		{
			m_lock->Unlock();
		}
	private:
		SpinLock* m_lock;
	};
}
